﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DatabaseLoaderImpl.cs" company="Marcin Jastrzebski">
//   Copyright (c) Marcin Jastrzebski (marcin@marcinj.net)
// </copyright>
// <summary>
//   The database manager implementation.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace mPassRT.Services
{
    using System.Collections.Generic;
    using System.Threading.Tasks;

    using KeePassLib;
    using KeePassLib.Interfaces;
    using KeePassLib.Keys;
    using KeePassLib.Serialization;

    using Microsoft.Practices.Unity;

    /// <summary>The database manager implementation.</summary>
    public class DatabaseLoaderImpl : IDatabaseLoader
    {
        #region Fields

        /// <summary>The current databases.</summary>
        private readonly Dictionary<string, PwDatabase> currentDatabases = new Dictionary<string, PwDatabase>();

        #endregion

        #region Public Properties

        /// <summary>Gets or sets the key provider.</summary>
        [Dependency]
        public IKeyProvider KeyProvider { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>Gets an existing database or loads it from disk.</summary>
        /// <param name="file">The file.</param>
        /// <returns>The <see cref="PwDatabase"/>the database</returns>
        public async Task<PwDatabase> GetDatabaseAsync(string file)
        {
            PwDatabase database;
            if (this.currentDatabases.TryGetValue(file, out database) == false)
            {
                database = await this.LoadDatabase(file);
            }

            return database;
        }

        #endregion

        #region Methods

        /// <summary>Loads the database from the file system.</summary>
        /// <param name="filePath">The file Path.</param>
        /// <returns>The loaded database or null.</returns>
        private async Task<PwDatabase> LoadDatabase(string filePath)
        {
            do
            {
                try
                {
                    CompositeKey key = await this.KeyProvider.GetKey(filePath, KeyOperation.Unlock);
                    if (key == null)
                    {
                        return null;
                    }

                    var database = new PwDatabase();
                    IOConnectionInfo descriptor = IOConnectionInfo.FromPath(filePath);

                    await Task.Run(() => database.Open(descriptor, key, new NullStatusLogger()));
                    this.currentDatabases.Add(filePath, database);
                    return database;
                }
                catch (InvalidCompositeKeyException)
                {
                    // invalid key - let user try again
                }
            }
            while (true);
        }

        #endregion
    }
}